﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Globalization;
using System.Web.UI;
using blackhouse.BlackApart.Business.Reservations;
using blackhouse.BlackApart.Business;

namespace blackhouse.BlackApart.Web {
    public class SearchState {

        #region Fields

        private bool parsed;
        private DateTime arrivalDate;
        private DateTime departureDate;
        private int peopleCount;
        private bool isSet;
        private bool isLastMinute;
        private bool preventShare = true;

        #endregion

        #region Properties

        public DateTime ArrivalDate {
            get {
                this.ParseIfNeeded();
                return this.arrivalDate;
            }
            private set { this.arrivalDate = value; this.SaveInContext(); }
        }

        public DateTime DepartureDate {
            get {
                this.ParseIfNeeded();
                return this.departureDate;
            }
            private set { this.departureDate = value; this.SaveInContext(); }
        }

        public int PeopleCount {
            get {
                this.ParseIfNeeded();
                return this.peopleCount;
            }
            private set { this.peopleCount = value; this.SaveInContext(); }
        }

        public bool IsSet {
            get {
                this.ParseIfNeeded();
                return this.isSet;
            }
            private set { this.isSet = value; this.SaveInContext(); }
        }

        public bool IsLastMinute {
            get {
                this.ParseIfNeeded();
                return this.isLastMinute;
            }
            private set { this.isLastMinute = value; this.SaveInContext(); }
        }

        #endregion

        #region Constructors

        private SearchState() {
            this.ArrivalDate = DateTime.Now;
            this.DepartureDate = DateTime.Now.AddDays(1);
            this.PeopleCount = 1;
            this.IsSet = false;
        }

        #endregion

        #region Methods

        private static SearchState empty;

        public static SearchState Empty {
            get {
                if (empty == null)
                    empty = new SearchState();
                return empty;
            }
        }

        public static SearchState GetFromContext() {
            SearchState state = null;
            if (HttpContext.Current.Items.Contains("SearchState"))
                state = HttpContext.Current.Items["SearchState"] as SearchState;
            if (state == null) {
                state = new SearchState();
                state.preventShare = false;
            }
            return state;
        }

        private void SaveInContext() {
            if (!preventShare)
                HttpContext.Current.Items["SearchState"] = this;
        }

        private void ParseIfNeeded() {
            if (this.Parse())
                this.SaveInContext();
        }

        public static string GetStringState(DateTime arrivalDate, DateTime departureDate, int peopleCount) {
            return GetState(arrivalDate, departureDate, peopleCount).ToString();
        }

        public static SearchState GetState(DateTime arrivalDate, DateTime departureDate, int peopleCount) {
            SearchState state = new SearchState();
            state.parsed = true; // blokuje mechanizm parsowania
            state.IsSet = true;
            state.ArrivalDate = arrivalDate;
            state.DepartureDate = departureDate;
            state.PeopleCount = peopleCount;
            return state;
        }

        private bool Parse() {
            if (parsed) return false;
            HttpContext context = HttpContext.Current;
            if (context == null) {
                parsed = true;
                return false;
            }

            DateTime ad, dd;
            int p;

            string op, sad, sdd, sp;

            op = context.Request.QueryString["search"];
            sad = context.Request.QueryString[UrlUtils.ParameterArrival];
            sdd = context.Request.QueryString[UrlUtils.ParameterDeparture];
            sp = context.Request.QueryString[UrlUtils.ParameterPersons];

            if (!string.IsNullOrEmpty(op)) {
                if (op.StartsWith("lastminute")) {
                    string[] sparts = op.Split(':');
                    if (sparts.Length == 2 && Int32.TryParse(sparts[1], out p)) {
                        parsed = true;
                        this.ArrivalDate = DateTime.Now.Date;
                        if (DateTime.Now.Hour >= 14)
                            this.ArrivalDate = this.ArrivalDate.AddDays(1);
                        this.DepartureDate = this.ArrivalDate.AddDays(1);
                        this.PeopleCount = p;
                        this.IsLastMinute = true;
                        this.IsSet = true;
                        return true;
                    }
                }
                if (op.Length >= 17) {
                    sad = op.Substring(0, 8);
                    sdd = op.Substring(8, 8);
                    sp = op.Substring(16);
                }
            }

            if (
                string.IsNullOrEmpty(sad)
                || string.IsNullOrEmpty(sdd)
                || string.IsNullOrEmpty(sp)) {
                parsed = true;
                return false;
            }

            if (
                !DateTime.TryParseExact(sad, "yyyyMMdd", CultureInfo.CurrentCulture, DateTimeStyles.None, out ad)
                || !DateTime.TryParseExact(sdd, "yyyyMMdd", CultureInfo.CurrentCulture, DateTimeStyles.None, out dd)
                || !Int32.TryParse(sp, out p)) {
                parsed = true;
                return false;
            }

            if (
                ad > dd
                || ad < DateTime.Now.Date
                || p <= 0
                || p > 100
                ) {
                parsed = true;
                return false;
            }

            parsed = true;
            this.ArrivalDate = ad;
            this.DepartureDate = dd;
            this.PeopleCount = p;
            this.IsSet = true;
            return true;
        }

        public override string ToString() {
            return
                this.ArrivalDate.ToString("yyyyMMdd") +
                this.DepartureDate.ToString("yyyyMMdd") +
                this.PeopleCount;
        }

        public void Visit(ISearchStateVisitor visitor) {
            visitor.Apply(this);
        }

        public FreeApartments GetSearchVariants() {
            return new FreeApartments(this.ArrivalDate, this.DepartureDate, this.PeopleCount);
        }

        public FreeApartments GetSearchVariants(int apartmentType) {
            FreeApartments freeAparts = new FreeApartments(this.ArrivalDate, this.DepartureDate, this.PeopleCount);
            freeAparts.FilterToApartmentType(apartmentType);
            return freeAparts;
        }

        #endregion

    }
}